/****************************************************************************//**
 * @file     clock_drv.c
 * @brief    CLOCK module driver file.
 * @version  V1.0.0
 * @date     March-2021
 * @author   Zhixin Semiconductor
 *
 * @note
 * Copyright (C) 2021-2022 Zhixin Semiconductor Ltd. All rights reserved.
 *
 *******************************************************************************/

//包含需要的头文件
#include "platform_cfg.h"	// 包含MCU平台配置信息的头文件
#include "common_drv.h"		// 包含SDK中常用信息的头文件

#include "clock_drv.h"




/** @addtogroup  Z20K14XM_Peripheral_Driver
 *  @{
 */

/** @defgroup Clock
 *  @brief Clock driver modules
 *  @{
 */

/** @defgroup Clock_Private_Type
 *  @{
 */
typedef volatile union
{
    struct {
        uint32_t PCKMD                   : 2;  /* [1:0]          r/w        */
        uint32_t RSVD_3_2                : 2;  /* [3:2]          r          */
        uint32_t CLKMUX                  : 3;  /* [6:4]          r/w        */
        uint32_t RSVD_7                  : 1;  /* [7]            r          */
        uint32_t CLKDIV                  : 4;  /* [11:8]         r/w        */
        uint32_t RSVD_15_12              : 4;  /* [15:12]        r          */
        uint32_t PWLK                    : 1;  /* [16]           r/w        */
        uint32_t RSVD_19_17              : 3;  /* [19:17]        r          */
        uint32_t PSUPVACEN               : 1;  /* [20]           r/w        */
        uint32_t PRSTB                   : 1;  /* [21]           r/w        */
        uint32_t RSVD_23_22              : 2;  /* [23:22]        r          */
        uint32_t PPR                     : 1;  /* [24]           r/w        */
        uint32_t PCLKMUXPR               : 1;  /* [25]           r/w        */
        uint32_t PCLKDIVPR               : 1;  /* [26]           r/w        */
        uint32_t PSUPVACPR               : 1;  /* [27]           r/w        */
        uint32_t RSVD_30_28              : 3;  /* [30:28]        r          */
        uint32_t LOCK                    : 1;  /* [31]           r/w        */
    } BF;
    uint32_t WORDVAL;
} ModuleClk_t;
/** @} end of group Clock_Private_Type*/


/** @defgroup Clock_PLL_Configure_Private_Defines
*  @{
*/

/** @} end of group Clock_PLL_Configure_Private_Type*/

/** @defgroup Clock_Private_Defines
 *  @{
 */
#define RTC         ((rtc_reg_t *) RTC_BASE_ADDR)            /*!< RTC Register */
#define RTC_W       ((rtc_reg_w_t *) RTC_BASE_ADDR)          /*!< RTC Register */
#define SCM         ((scm_reg_t *) SCM_BASE_ADDR)            /*!< System Control Register */
#define SCM_W       ((scm_reg_w_t *) SCM_BASE_ADDR)          /*!< System Control Register */
#define SCC         ((scc_reg_t *) SCC_BASE_ADDR)            /*!< System Clock controller registers */
#define SCC_W       ((scc_reg_w_t *) SCC_BASE_ADDR)          /*!< System Clock controller registers */
#define PMU         ((pmu_reg_t *) PMU_BASE_ADDR)            /*!< PMU Register */
#define PMU_W       ((pmu_reg_w_t *) PMU_BASE_ADDR)          /*!< PMU Register */
#define PARCC       ((parcc_reg_t *) PARCC_BASE_ADDR)        /*!< Peripheral clock controller registers */
#define PARCC_W     ((parcc_reg_w_t *) PARCC_BASE_ADDR)        /*!< Peripheral clock controller registers */


#define PMU_UNLOCK_SEQUENCE   (0x94730000UL)
#define CLK_WAIT_CNT          100000U			//it is more than 70000
#define CLK_OSC32K_WAIT_CNT   5000000U


/** @} end of group Clock_Private_Defines */

/** @defgroup Clock_Private_Variables
 *  @{
 */
/**
 *  @brief SCC IRQHandler callback function pointer array
 */
static isr_cb_t * sccIsrCbFunc[CLK_INT_ALL]= {NULL, NULL, NULL};

/** @} end of group Clock_Private_Variables */

/** @defgroup Clock_Global_Variables
 *  @{
 */

/** @} end of group Clock_Global_Variables */

/** @defgroup Clock_Private_FunctionDeclaration
 *  @{
 */
void SCC_DriverIRQHandler(void);

/** @} end of group Clock_Private_FunctionDeclaration */

/** @defgroup Clock_Private_Functions
 *  @{
 */

static uint32_t CLK_GetSysClkFreq(uint32_t oscFreq);


/***************************************************************************//**
 * @brief  SCC IRQHandler function
 *
 * @param  none
 *
 * @return none
 *
 ******************************************************************************/
void SCC_DriverIRQHandler(void)
{
    if(SCC->SCC_OSCCS.OSCLOC != 0U)
    {
        if(SCC->SCC_OSCCS.LOCK != 0U)
        {
            /* unlock this register */
            SCC_W->SCC_OSCCS = 0x5B000000U;
        }
        /* clear int status */
        SCC->SCC_OSCCS.OSCLOC = 1U;
        /* lock */
        SCC->SCC_OSCCS.LOCK = 1U;
        
        if(sccIsrCbFunc[CLK_INT_HSOSCLOC] != NULL)
        {
            sccIsrCbFunc[CLK_INT_HSOSCLOC]();
        }
        else
        {
            CLK_HSOSCMonitorDisable();
        }
    }
    
    if(SCC->SCC_FIRCCS.FIRCLOC != 0U)
    {
        if(SCC->SCC_FIRCCS.LOCK != 0U)
        {
            /* unlock this register */
            SCC_W->SCC_FIRCCS = 0x5B000000U;
        }
        /* clear int status */
        SCC->SCC_FIRCCS.FIRCLOC = 1U;
        /* lock */
        SCC->SCC_FIRCCS.LOCK = 1U;
        
        if(sccIsrCbFunc[CLK_INT_FIRCLOC] != NULL)
        {
            sccIsrCbFunc[CLK_INT_FIRCLOC]();
        }
        else
        {
            CLK_FIRCMonitorDisable();
        }
    }

    if(SCC->SCC_SPLLCS.LOL != 0U)
    {
        if(SCC->SCC_SPLLCS.LOCK != 0U)
        {
            /* unlock this register */
            SCC_W->SCC_SPLLCS = 0x5B000000U;
        }

        /* clear int status */
        SCC->SCC_SPLLCS.LOL = 1U;
        /* lock */
        SCC->SCC_SPLLCS.LOCK = 1U;
        
        if(sccIsrCbFunc[CLK_INT_PLLLOC] != NULL)
        {
            sccIsrCbFunc[CLK_INT_PLLLOC]();
        }
        else
        {
            CLK_PLLMonitorDisable();
        }
    }
    CORE_DSB();
}

/***************************************************************************//**
 * @brief      get system clock frequency before divider
 *
 * @param[in]  oscFreq: frequency of the OSC clock
 *
 * @return    ret  the clock frequency. If return 0, there is some error.
 *
 ******************************************************************************/
static uint32_t CLK_GetSysClkFreq(uint32_t oscFreq)
{
    uint32_t ret = 0U;
    
    if(2U == SCC->SCC_CST.SCS)
    {
        ret = oscFreq;
    }

    if(1U == SCC->SCC_CST.SCS)
    {
        ret = 64000000UL;
    }

    else if(3U == SCC->SCC_CST.SCS)
    {
        if(0U == SCC->SCC_SPLLCFG1.REFCKS)
        {
            ret = CLK_GetPLLFreq(PLL_FIRC_CLK, oscFreq);
        }
        /* 1U == sccRegBfPtr->SCC_SPLLCFG1.REFCKS */
        else
        {
            ret = CLK_GetPLLFreq(PLL_HSOSC_CLK, oscFreq);
        }
    }

    return ret;
}

/** @} end of group Clock_Private_Functions */

/** @defgroup Clock_Public_Functions
 *  @{
 */


/***************************************************************************//**
 * @brief      Config and enable FIRC clock
 *
 * @param[in]  stopModeEn:  Enable/Disable FIRC in stop mode
 *                              -ENABLE
 *                              -DISABLE
 *
 * @return none
 *
 ******************************************************************************/
void CLK_FIRCEnable(ControlState_t stopModeEn)
{
    if(SCC->SCC_FIRCCS.LOCK != 0U)
    {
        /* unlock this register */
        SCC_W->SCC_FIRCCS = 0x5B000000U;
    }

    SCC->SCC_FIRCCS.FIRCSTOPEN = (uint32_t)stopModeEn;
    SCC->SCC_FIRCCS.FIRCEN = 1U;

    /* lock this register */
    SCC->SCC_FIRCCS.LOCK = 1U;
}

/***************************************************************************//**
 * @brief      Config and enable PLL clock
 *
 * @param[in]  stopModeEn:  Enable/Disable PLL in stop mode.
 *                              -ENABLE
 *                              -DISABLE
 *
 * @return none
 *
 ******************************************************************************/
void CLK_PLLEnable(ControlState_t stopModeEn)
{
    if(SCC->SCC_SPLLCS.LOCK != 0U)
    {
        /* unlock this register */
        SCC_W->SCC_SPLLCS = 0x5B000000U;
    }

	SCC->SCC_SPLLCS.LOLINTEN = 0;	// disable LOL interrupt
    SCC->SCC_SPLLCS.RDYEN = 1U;		// SPLL ready bit detector enable. this is needful.
    SCC->SCC_SPLLCS.SPLLSTOPEN = (uint32_t)stopModeEn;
	SCC->SCC_SPLLCS.LOCKWIN = 3U;	// set PLL lock window
	SCC->SCC_SPLLCS.SPLLEN = 1U;	// enable PLL

    /* lock this register */
    SCC->SCC_SPLLCS.LOCK = 1U;

    if(SUCC == CLK_WaitClkReady(CLK_SRC_PLL))
    {
		SCC_W->SCC_SPLLCS = 0x5B000000U;// unlock this register
        SCC->SCC_SPLLCS.OUTEN = 1U;		// enable SPLL Clock out
        SCC->SCC_SPLLCS.RDYEN = 1U;		// SPLL ready bit detector enable
        SCC->SCC_SPLLCS.LOCK = 1U;		// lock this register
    }
}

/***************************************************************************//**
 * @brief      Config and enable  HSOSC clock
 *
 * @param[in]  freqMode:  It selects the frequency mode of HSOSC
 * @param[in]  stopModeEn:  Enable/Disable HSOSC in stop mode.
 * @param[in]  mode: select OSC mode. It selects from crystal oscillator or 
 *                   external square wave clock source.
 *
 * @return status
 *         ERR - some error.
 *         SUCC - successful
 *
 ******************************************************************************/
ResultStatus_t CLK_HSOSCEnable(CLK_OscFreqMode_t freqMode, 
                                 ControlState_t stopModeEn, 
                                 CLK_OscMode_t mode)
{
    if(SCC->SCC_OSCCFG.LOCK != 0U)
    {
        /* unlock this register */
        SCC_W->SCC_OSCCFG = 0x5B000000U;
    }
    SCC->SCC_OSCCFG.HFREQ = (uint32_t)freqMode;
    SCC->SCC_OSCCFG.EXCLKS = (uint32_t)mode;
    SCC->SCC_OSCCFG.OLMEN = 1U;
    /* lock */
    SCC->SCC_OSCCFG.LOCK = 1U;

    if(SCC->SCC_OSCCS.LOCK != 0U)
    {
        /* unlock this register */
        SCC_W->SCC_OSCCS = 0x5B000000U;
    }
    SCC->SCC_OSCCS.OSCSTOPEN = (uint32_t)stopModeEn;

    SCC->SCC_OSCCS.OSCEN = 1U;
    SCC->SCC_OSCCS.LOCK = 1U;
    /* wait for clock ready */
    return CLK_WaitClkReady(CLK_SRC_HSOSC);
}

/***************************************************************************//**
 * @brief      Select system clock.
 *
 * @param[in]  clk: select the clock source
 *                  -CLK_SYS_HSOSC
 *                  -CLK_SYS_FIRC
 *                  -CLK_SYS_PLL
 *
 * @return 
 *         SUCC: the system clock is selected successfully
 *         ERR: fail
 * @note The selected clock source has to be ready
 *       before call this function.
 *
 ******************************************************************************/
ResultStatus_t CLK_SysClkSrc(CLK_System_t clk)
{
    if(CLK_SYS_FIRC == clk)
    {
        if(CLK_WaitClkReady(CLK_SRC_FIRC) != SUCC)
        {
            return ERR;
        }

        if(SCC->SCC_CFG.LOCK != 0U)
        {
            /* unlock this register */
            SCC_W->SCC_CFG = 0x5B000000U;
        }
        /* select sys clock source */
        SCC_W->SCC_CFG = (SCC_W->SCC_CFG & 0xFFF8FFFFU) | (1UL << 16U);

        SCC->SCC_CFG.LOCK = 1U;

        return SUCC;
    }
    else if(CLK_SYS_HSOSC == clk)
    {
        if(CLK_WaitClkReady(CLK_SRC_HSOSC) != SUCC)
        {
            return ERR;
        }

        if(SCC->SCC_CFG.LOCK != 0U)
        {
            /* unlock this register */
            SCC_W->SCC_CFG = 0x5B000000U;
        }
        /* select sys clock source */
        SCC_W->SCC_CFG = (SCC_W->SCC_CFG & 0xFFF8FFFFU) | (1UL << 17U);

        SCC->SCC_CFG.LOCK = 1;

        return SUCC;
    }
    else if(CLK_SYS_PLL == clk)
    {
        if(CLK_WaitClkReady(CLK_SRC_PLL) != SUCC)
        {
            return ERR;
        }

        if(SCC->SCC_CFG.LOCK != 0U)
        {
            /* unlock this register */
            SCC_W->SCC_CFG = 0x5B000000U;
        }
        /* select sys clock source */
        SCC_W->SCC_CFG = (SCC_W->SCC_CFG & 0xFFF8FFFFU) | (3UL << 16U);

        SCC->SCC_CFG.LOCK = 1;

        return SUCC;
    }
    else
    {
        return ERR;
    }
}

/***************************************************************************//**
 * @brief      Get system clock source.
 *
 * @param[in]  none.
 *
 * @return 
 *          -CLK_SYS_FIRC
 *          -CLK_SYS_HSOSC
 *          -CLK_SYS_PLL
 *
 ******************************************************************************/
CLK_System_t CLK_GetSysClkSrc(void)
{
    if(SCC->SCC_CST.SCS == (uint32_t)CLK_SYS_FIRC)
    {
        return CLK_SYS_FIRC;
    }
    else if(SCC->SCC_CST.SCS == (uint32_t)CLK_SYS_HSOSC)
    {
        return CLK_SYS_HSOSC;
    }
    /* SCC->SCC_CST.SCS == CLK_SYS_PLL */
    else
    {
        return CLK_SYS_PLL;
    }
}

/***************************************************************************//**
 * @brief      Disable FIRC clock
 *
 * @param[in]  none.
 *
 * @return none
 *
 ******************************************************************************/
void CLK_FIRCDisable(void)
{
    if(SCC->SCC_FIRCCS.LOCK != 0U)
    {
        /* unlock this register */
        SCC_W->SCC_FIRCCS = 0x5B000000;
    }

    SCC->SCC_FIRCCS.FIRCEN = 0;

    /* lock this register */
    SCC->SCC_FIRCCS.LOCK = 1;
}

/***************************************************************************//**
 * @brief      Disable PLL clock
 *
 * @param[in]  none.
 *
 * @return none
 *
 ******************************************************************************/
void CLK_PLLDisable(void)
{
    if(SCC->SCC_SPLLCS.LOCK != 0U)
    {
        /* unlock this register */
        SCC_W->SCC_SPLLCS = 0x5B000000;
    }

    SCC->SCC_SPLLCS.SPLLEN = 0;

    SCC->SCC_SPLLCS.OUTEN = 0;

    /* lock this register */
    SCC->SCC_SPLLCS.LOCK = 1;
}

/***************************************************************************//**
 * @brief      Select PLL reference clock
 *
 * @param[in]  pll_ref_clk: PLL reference clock
 *                              -PLL_HSOSC_CLK
 *                              -PLL_FIRC_CLK
 *
 * @return none
 *
 ******************************************************************************/
void CLK_PLLRefClockSelect(CLK_PLLRefClk_t pll_ref_clk)
{
    if(SCC->SCC_SPLLCFG1.LOCK != 0U)
    {
        /* unlock this register */
        SCC_W->SCC_SPLLCFG1 = 0x5B000000;
    }

    /*Select OSC or FIRC as PLL reference clock*/
    SCC->SCC_SPLLCFG1.REFCKS = (uint32_t)pll_ref_clk;

    /* lock this register */
    SCC->SCC_SPLLCFG1.LOCK = 1;
}

/***************************************************************************//**
 * @brief      Get PLL output freqency
 *
 * @param[in]  pll_ref_clk: PLL reference clock
 *                              -PLL_HSOSC_CLK
 *                              -PLL_FIRC_CLK
 *
 * @return 
 *            PLL output freqency.
 *
 ******************************************************************************/
uint32_t CLK_GetPLLFreq(CLK_PLLRefClk_t pll_ref_clk, uint32_t oscFreq)
{
    uint32_t postDiv;
    uint32_t preDiv;
    uint32_t mult;
    uint32_t preScaler = 0U;
    uint32_t pllOutFreq = 0U;
    if(SCC->SCC_SPLLCFG1.LOCK != 0U)
    {
        /* unlock this register */
        SCC_W->SCC_SPLLCFG1 = 0x5B000000;
    }

    postDiv = SCC->SCC_SPLLCFG1.POSTDIV;
    preDiv = SCC->SCC_SPLLCFG1.PREDIV;
    mult = SCC->SCC_SPLLCFG1.MULT;
    if(SCC->SCC_SPLLCFG1.FBPRESEN == 1U)
    {
        preScaler = 2;
    }
    else //if(SCC->SCC_SPLLCFG1.FBPRESEN == 0U)
    {
        preScaler = 1;
    }
    /* lock this register */
    SCC->SCC_SPLLCFG1.LOCK = 1;

    if(pll_ref_clk == PLL_HSOSC_CLK)
    {
        pllOutFreq = oscFreq*mult*preScaler/((postDiv*2U)*((uint32_t)1U<<preDiv));
    }
    if(pll_ref_clk == PLL_FIRC_CLK)
    {
        pllOutFreq = 64000000U*mult*preScaler/((postDiv*2U)*((uint32_t)1U<<preDiv));
    }

    return pllOutFreq;
}

/***************************************************************************//**
 * @brief      Set PLL output clock configuration
 *
 * @param[in]  pll_config: pointer to the PLL configure struct
 *
 * @return 
 *            Configure PLL output clock.
 *
 * @note    According to the following formula to configure the desired PLL out freqency:
 *
 *           pllOutFreq = refClock * mult * preScaler / (postDivEnum*preDivEnum)
 *
 *           1. 80M PLL output configuration(use HSOSC as clock reference)
 *              CLK_PLLConfig_t PLLHSOSCSet80M =
 *              {
 *                  .pllPreDivider = PLL_PRE_DIV_VALUE_4,         
 *                  .pllPostDivider = PLL_POST_DIV_VALUE_12,        
 *                  .pllMultiplier = 48,                           
 *                  .pllRefClock = PLL_HSOSC_CLK,                  
 *                  .pllPreScaler = PLL_SCALER_VALUE_2,       
 *              };
 *
 *           2. 120M PLL output configuration(use HSOSC as clock reference)
 *              CLK_PLLConfig_t PLLHSOSCSet120M =
 *              {
 *                  .pllPreDivider = PLL_PRE_DIV_VALUE_4,              
 *                  .pllPostDivider = PLL_POST_DIV_VALUE_8,            
 *                  .pllMultiplier = 48,                            
 *                  .pllRefClock = PLL_HSOSC_CLK,                  
 *                  .pllPreScaler = PLL_SCALER_VALUE_2,             
 *              };
 *
 ******************************************************************************/
void CLK_PLLConfig(const CLK_PLLConfig_t *pll_config)
{
    if(SCC->SCC_SPLLCFG1.LOCK != 0U)
    {
        SCC_W->SCC_SPLLCFG1 = 0x5B000000;	// unlock this register
    }

    // Set up the PLL configuration register
	SCC->SCC_SPLLCFG1.POSTDIV = (uint32_t)(pll_config->pllPostDivider);
    SCC->SCC_SPLLCFG1.PREDIV = (uint32_t)(pll_config->pllPreDivider);
    SCC->SCC_SPLLCFG1.MULT = pll_config->pllMultiplier;
    SCC->SCC_SPLLCFG1.FBPRESEN = (uint32_t)(pll_config->pllPreScaler);
    SCC->SCC_SPLLCFG1.REFCKS = (uint32_t)(pll_config->pllRefClock);
	
	SCC->SCC_SPLLCS.LOLINTEN = 0;	// disable LOL interrupt
	SCC->SCC_SPLLCS.RDYEN = 1U;		// SPLL ready bit detector enable. this is needful.
	SCC->SCC_SPLLCS.LOCKWIN = 3U;	// set PLL lock window
	SCC->SCC_SPLLCS.SPLLEN = 1U;	// enable PLL
	
    SCC->SCC_SPLLCS.LOCK = 1U;		// lock this register

    if(CLK_WaitClkReady(CLK_SRC_PLL) == SUCC)
    {
        SCC_W->SCC_SPLLCS = 0x5B000000U;// unlock this register
        SCC->SCC_SPLLCS.OUTEN = 1U;		// enable SPLL Clock out
        SCC->SCC_SPLLCS.RDYEN = 0U;		// SPLL ready bit detector disable
        SCC->SCC_SPLLCS.LOCK = 1U;		// lock this register
    }
}

/***************************************************************************//**
 * @brief      Disable HSOSC clock
 *
 * @param[in]  none.
 *
 * @return none
 *
 ******************************************************************************/
void CLK_HSOSCDisable(void)
{
    if(SCC->SCC_OSCCS.LOCK != 0U)
    {
        /* unlock this register */
        SCC_W->SCC_OSCCS = 0x5B000000;
    }
    if(SCC->SCC_OSCCFG.LOCK != 0U)
    {
        /* unlock this register */
        SCC_W->SCC_OSCCFG = 0x5B000000U;
    }
    
    SCC->SCC_OSCCS.OSCEN = 0U;
    SCC->SCC_OSCCFG.OLMEN = 0U;

    /* lock */
    SCC->SCC_OSCCS.LOCK = 1U;
    SCC->SCC_OSCCFG.LOCK = 1U;
}

/***************************************************************************//**
 * @brief      Config and Enable HSOSC loss of clock monitor
 *
 * @param[in]  act: select the action when loss of clock is detected.
 *                  -CLK_MON_INT
 *                  -CLK_MON_RST
 *
 * @return none
 *
 ******************************************************************************/
void CLK_HSOSCMonitorEnable(CLK_MonitorAct_t act)
{
    if(SCC->SCC_OSCCS.LOCK != 0U)
    {
        /* unlock this register */
        SCC_W->SCC_OSCCS = 0x5B000000;
    }

    SCC->SCC_OSCCS.OSCCMRE = (uint32_t)act;

    SCC->SCC_OSCCS.OSCCME = 1;
    SCC->SCC_OSCCS.OSCLOCINTEN = 1;
    /* lock */
    SCC->SCC_OSCCS.LOCK = 1;
}

/***************************************************************************//**
 * @brief      Disable HSOSC loss of clock monitor
 *
 * @param[in]  none.
 *
 * @return none
 *
 ******************************************************************************/
void CLK_HSOSCMonitorDisable(void)
{
    if(SCC->SCC_OSCCS.LOCK != 0U)
    {
        /* unlock this register */
        SCC_W->SCC_OSCCS = 0x5B000000;
    }

    SCC->SCC_OSCCS.OSCCME = 0;
    /* lock */
    SCC->SCC_OSCCS.LOCK = 1;
}

/***************************************************************************//**
 * @brief      Config and Enable FIRC loss of clock monitor
 *
 * @param[in]  act: select the action when loss of clock is detected.
 *                  -CLK_MON_INT
 *                  -CLK_MON_RST
 *
 * @return none
 *
 ******************************************************************************/
void CLK_FIRCMonitorEnable(CLK_MonitorAct_t act)
{
    if(SCC->SCC_FIRCCS.LOCK != 0U)
    {
        /* unlock this register */
        SCC_W->SCC_FIRCCS = 0x5B000000;
    }

    SCC->SCC_FIRCCS.FIRCCMRE = (uint32_t)act;

    SCC->SCC_FIRCCS.FIRCCME = 1;
    SCC->SCC_FIRCCS.FIRCLOCINTEN = 1;
    /* lock */
    SCC->SCC_FIRCCS.LOCK = 1;
}

/***************************************************************************//**
 * @brief      Config and Enable PLL loss of clock monitor
 *
 * @param[in]  act: select the action when loss of clock is detected.
 *                  -CLK_MON_INT
 *                  -CLK_MON_RST
 *
 * @return none
 *
 ******************************************************************************/
void CLK_PLLMonitorEnable(CLK_MonitorAct_t act)
{
    if(SCC->SCC_SPLLCS.LOCK != 0U)
    {
        /* unlock this register */
        SCC_W->SCC_SPLLCS = 0x5B000000;
    }

    SCC->SCC_SPLLCS.LOLRESTEN = (uint32_t)act;

    SCC->SCC_SPLLCS.RDYEN = 1;
    SCC->SCC_SPLLCS.LOLINTEN = 1;
    /* lock */
    SCC->SCC_SPLLCS.LOCK = 1;
}

/***************************************************************************//**
 * @brief      Config and Enable FIRC loss of clock monitor
 *
 * @param[in]  none
 *
 * @return none
 *
 ******************************************************************************/
void CLK_FIRCMonitorDisable(void)
{
    if(SCC->SCC_FIRCCS.LOCK != 0U)
    {
        /* unlock this register */
        SCC_W->SCC_FIRCCS = 0x5B000000;
    }

    SCC->SCC_FIRCCS.FIRCCME = 0;
    /* lock */
    SCC->SCC_FIRCCS.LOCK = 1;
}

/***************************************************************************//**
 * @brief      Config and Enable SPLL160M loss of clock detector
 *
 * @param[in]  none
 *
 * @return none
 *
 ******************************************************************************/
void CLK_PLLMonitorDisable(void)
{
    if(SCC->SCC_SPLLCS.LOCK != 0U)
    {
        /* unlock this register */
        SCC_W->SCC_SPLLCS = 0x5B000000;
    }

    SCC->SCC_SPLLCS.RDYEN = 0;
    /* lock */
    SCC->SCC_SPLLCS.LOCK = 1;
}

/***************************************************************************//**
 * @brief      Config and Enable LPO32K clock
 *
 * @param[in]  none
 *
 * @return none
 *
 ******************************************************************************/
void CLK_LPO32KEnable(void)
{
    PMU_W->PMU_LOCK = PMU_UNLOCK_SEQUENCE;
    PMU->PMU_LPO_32K_CFG.LPO_CLK_DIS = 0;
    PMU->PMU_LOCK.LOCK = 1U;
}

/***************************************************************************//**
 * @brief      Disable LPO32K clock
 *
 * @param[in]  none.
 *
 * @return none
 *
 ******************************************************************************/
void CLK_LPO32KDisable(void)
{
    PMU_W->PMU_LOCK = PMU_UNLOCK_SEQUENCE;
    PMU->PMU_LPO_32K_CFG.LPO_CLK_DIS = 1;
    PMU->PMU_LOCK.LOCK = 1U;
}

/***************************************************************************//**
 * @brief      Config and Enable OSC32K clock
 *
 * @param[in]  mode:  Select internal/external mode.
 *                    -CLK_OSC_XTAL
 *                    -CLK_OSC_EXT_SRC
 *
 * @return none
 *
 ******************************************************************************/
void CLK_OSC32KEnable(CLK_OscMode_t mode)
{
    if(RTC->RTC_LOCKR.LOCK != NULL)
    {
        RTC_W->RTC_LOCKR = 0x98670000U;
    }
    if( CLK_OSC_XTAL == mode)
    {
        RTC->RTC_CSR.EXTAL_32K_EN = 0U;
        RTC->RTC_CSR.CRYSTAL_EN = 1U;
    }
    else
    {
        RTC->RTC_CSR.EXTAL_32K_EN = 1U;
        RTC->RTC_CSR.CRYSTAL_EN = 0U;
    }
    RTC->RTC_LOCKR.LOCK = 1U;
}

/***************************************************************************//**
 * @brief      Disable OSC32K clock
 *
 * @param[in]  none
 *
 * @return none
 *
 ******************************************************************************/
void CLK_OSC32KDisable(void)
{
    if(RTC->RTC_LOCKR.LOCK != NULL)
    {
        RTC_W->RTC_LOCKR = 0x98670000U;
    }
    RTC->RTC_CSR.EXTAL_32K_EN = 0U;
    RTC->RTC_CSR.CRYSTAL_EN = 0U;
    RTC->RTC_LOCKR.LOCK = 1U;
}
/***************************************************************************//**
 * @brief      Set clock divider
 *
 * @param[in]  module: select which module clock to enable.
 *                     
 * @param[in] divider: Select the clock divider: CLK_DIV_1...CLK_DIV_16.
 * @return     none
 *
 ******************************************************************************/
void CLK_SetClkDivider(CLK_Module_t module, CLK_Divider_t divider)
{
    ModuleClk_t *mod_p = (ModuleClk_t *)(PARCC_BASE_ADDR + (uint32_t)module);
    switch(module)
    {
        case CLK_EWDT:
        case CLK_STIM:
        case CLK_TIM0:
        case CLK_TIM1:
        case CLK_TIM2:
        case CLK_TIM3:
        case CLK_MCPWM0:
        case CLK_MCPWM1:
        case CLK_TDG0:
        case CLK_TDG1:
        case CLK_CAN0:
        case CLK_CAN1:
        case CLK_CAN2:
        case CLK_CAN3:
        case CLK_CAN4:
        case CLK_CAN5:
        case CLK_CAN6:
        case CLK_CAN7:
        case CLK_UART0:
        case CLK_UART1:
        case CLK_UART2:
        case CLK_UART3:
        case CLK_UART4:
        case CLK_UART5:
        case CLK_SPI0:
        case CLK_SPI1:
        case CLK_SPI2:
        case CLK_SPI3:
        case CLK_I2C0:    
        case CLK_I2C1: 
        case CLK_I2S0:
        case CLK_I2S1:
        case CLK_ADC0:
        case CLK_ADC1:
        case CLK_FLASH:
        case CLK_PORTA:
        case CLK_PORTB:
        case CLK_PORTC:
        case CLK_PORTD:
        case CLK_PORTE:
            if(mod_p->BF.LOCK != 0U)
            {
                /* unlock this register */
                mod_p->WORDVAL = 0x5B000000U;
            }

            mod_p->BF.CLKDIV = (uint32_t)divider;
            mod_p->BF.LOCK = 1U;
            break;

        case CLK_CORE:
            if(SCC->SCC_CFG.LOCK != 0U)
            {
                /* unlock this register */
                SCC_W->SCC_CFG = 0x5B000000U;
            }

            SCC_W->SCC_CFG = (SCC_W->SCC_CFG & 0xFFFFF0FFU) | ((uint32_t)divider << 8U);
            SCC->SCC_CFG.LOCK = 1;
            break;

        case CLK_BUS:
            if(SCC->SCC_CFG.LOCK != 0U)
            {
                /* unlock this register */
                SCC_W->SCC_CFG = 0x5B000000U;
            }

            SCC_W->SCC_CFG = (SCC_W->SCC_CFG & 0xFFFFFF0FU) | ((uint32_t)divider << 4U);
            SCC->SCC_CFG.LOCK = 1U;
            break;

        case CLK_SLOW:
            if(SCC->SCC_CFG.LOCK != 0U)
            {
                /* unlock this register */
                SCC_W->SCC_CFG = 0x5B000000U;
            }

            SCC_W->SCC_CFG = (SCC_W->SCC_CFG & 0xFFFFFFF0U) | (uint32_t)divider;
            SCC->SCC_CFG.LOCK = 1U;
            break;

        default:
            break;
    }
}

/***************************************************************************//**
 * @brief      Select clock source for module
 *
 * @param[in]  module: select which module clock to enable.
 *                     
 * @param[in]  clockSource: select clock source
 *                          -CLK_SRC_NO
 *                          -CLK_SRC_LPO32K
 *                          -CLK_SRC_OSC32K
 *                          -CLK_SRC_FIRC
 *                          -CLK_SRC_HSOSC
 *                          -CLK_SRC_PLL
 * @return 
 *         - SUCC
 *         - ERR: the input parameter is unreasonable.
 *
 ******************************************************************************/
ResultStatus_t CLK_ModuleSrc(CLK_Module_t module, CLK_Src_t clockSource)
{
    ModuleClk_t *mod_p = (ModuleClk_t *)(PARCC_BASE_ADDR + (uint32_t)module);
    volatile ResultStatus_t res = SUCC;

    switch(module)
    {
        case CLK_STIM:
        case CLK_TIM0:
        case CLK_TIM1:
        case CLK_TIM2:
        case CLK_TIM3:
        case CLK_MCPWM0:
        case CLK_MCPWM1:
        case CLK_TDG0:
        case CLK_TDG1:
        case CLK_UART0:
        case CLK_UART1:
        case CLK_UART2:
        case CLK_UART3:
        case CLK_UART4:
        case CLK_UART5:
        case CLK_SPI0:
        case CLK_SPI1:
        case CLK_SPI2:
        case CLK_SPI3:
        case CLK_I2C0:    
        case CLK_I2C1: 
        case CLK_I2S0:
        case CLK_I2S1:
        
            if(mod_p->BF.LOCK != 0U)
            {
                /* unlock this register */
                mod_p->WORDVAL = 0x5B000000U;
            }
            if(CLK_SRC_LPO32K == clockSource)
            {
                mod_p->BF.CLKMUX = (uint32_t)clockSource;
            }
            else if(CLK_SRC_OSC32K == clockSource)
            {
                mod_p->BF.CLKMUX = (uint32_t)clockSource;
            }
            else if(CLK_SRC_FIRC == clockSource)
            {
                mod_p->BF.CLKMUX = (uint32_t)clockSource;
            }
            else if(CLK_SRC_HSOSC == clockSource)
            {
                mod_p->BF.CLKMUX = (uint32_t)clockSource;
            }
            else if(CLK_SRC_PLL == clockSource)
            {
                mod_p->BF.CLKMUX = (uint32_t)clockSource;
            }
            else if(CLK_SRC_NO == clockSource)
            {
                mod_p->BF.CLKMUX = (uint32_t)clockSource;
            }
            else
            {
                res = ERR;
            }
            mod_p->BF.LOCK = 1U;
            break;
        case CLK_WDOG:
            if(mod_p->BF.LOCK  != 0U)
            {
                /* unlock this register */
                mod_p->WORDVAL = 0x5B000000U;
            }
            if(CLK_SRC_NO == clockSource)
            {
                mod_p->BF.CLKMUX = (uint32_t)clockSource;
            }
            else
            {
                res = ERR;
            }
            mod_p->BF.LOCK = 1U;
            break;
        case CLK_CAN0:
        case CLK_CAN1:
        case CLK_CAN2:
        case CLK_CAN3:
        case CLK_CAN4:
        case CLK_CAN5:
        case CLK_CAN6:
        case CLK_CAN7:
            if(mod_p->BF.LOCK != 0U)
            {
                /* unlock this register */
                mod_p->WORDVAL = 0x5B000000U;
            }
            if(CLK_SRC_FIRC == clockSource)
            {
                mod_p->BF.CLKMUX = (uint32_t)clockSource;
            }
            else if(CLK_SRC_HSOSC == clockSource)
            {
                mod_p->BF.CLKMUX = (uint32_t)clockSource;
            }
            else if(CLK_SRC_PLL == clockSource)
            {
                mod_p->BF.CLKMUX = (uint32_t)clockSource;
            }
            else if(CLK_SRC_NO == clockSource)
            {
                mod_p->BF.CLKMUX = (uint32_t)clockSource;
            }
            else
            {
                res = ERR;
            }
            mod_p->BF.LOCK = 1U;
            break;

        case CLK_FLASH:
            if(mod_p->BF.LOCK  != 0U)
            {
                /* unlock this register */
                mod_p->WORDVAL = 0x5B000000U;
            }
            if(CLK_SRC_FIRC == clockSource)
            {
                mod_p->BF.CLKMUX = (uint32_t)clockSource;
            }
            else if(CLK_SRC_HSOSC == clockSource)
            {
                mod_p->BF.CLKMUX = (uint32_t)clockSource;
            }
            else if(CLK_SRC_PLL == clockSource)
            {
                mod_p->BF.CLKMUX = (uint32_t)clockSource;
            }
            else if(CLK_SRC_SLOW == clockSource)
            {
                mod_p->BF.CLKMUX = (uint32_t)clockSource;
            }
            else if(CLK_SRC_NO == clockSource)
            {
                mod_p->BF.CLKMUX = (uint32_t)clockSource;
            }
            else
            {
                res = ERR;
            }
            mod_p->BF.LOCK = 1U;
            break;

        case CLK_EWDT:
        case CLK_ADC0:
        case CLK_ADC1:
        case CLK_PORTA:
        case CLK_PORTB:
        case CLK_PORTC:
        case CLK_PORTD:
        case CLK_PORTE:
            if(mod_p->BF.LOCK  != 0U)
            {
                /* unlock this register */
                mod_p->WORDVAL = 0x5B000000U;
            }
            if(CLK_SRC_LPO32K == clockSource)
            {
                mod_p->BF.CLKMUX = (uint32_t)clockSource;
            }
            else if(CLK_SRC_OSC32K == clockSource)
            {
                mod_p->BF.CLKMUX = (uint32_t)clockSource;
            }
            else if(CLK_SRC_FIRC == clockSource)
            {
                mod_p->BF.CLKMUX = (uint32_t)clockSource;
            }
            else if(CLK_SRC_HSOSC == clockSource)
            {
                mod_p->BF.CLKMUX = (uint32_t)clockSource;
            }
            else if(CLK_SRC_NO == clockSource)
            {
                mod_p->BF.CLKMUX = (uint32_t)clockSource;
            }
            else
            {
                res = ERR;
            }
            mod_p->BF.LOCK = 1U;
            break;

        default:
            res = ERR;
            break;
    }
    return res;
}


/***************************************************************************//**
 * @brief      get module clock frequency before divider
 *
 * @param[in]  module: select the module
 * @param[in]  oscFreq: frequency of the OSC clock
 *
 * @return     The clock frequency. If return 0, there is some error.
 *
 ******************************************************************************/
uint32_t CLK_GetModuleClkFreq(CLK_Module_t module,uint32_t oscFreq)
{
    ModuleClk_t *mod_p = (ModuleClk_t *)(PARCC_BASE_ADDR + (uint32_t)module);
    uint32_t freq = 0,div = 1;

    switch(module)
    {        
        case CLK_EWDT:
        case CLK_STIM:
        case CLK_TIM0:
        case CLK_TIM1:
        case CLK_TIM2:
        case CLK_TIM3:
        case CLK_MCPWM0:
        case CLK_MCPWM1:
        case CLK_TDG0:
        case CLK_TDG1:
        case CLK_CAN0:
        case CLK_CAN1:
        case CLK_CAN2:
        case CLK_CAN3:
        case CLK_CAN4:
        case CLK_CAN5:
        case CLK_CAN6:
        case CLK_CAN7:
        case CLK_UART0:
        case CLK_UART1:
        case CLK_UART2:
        case CLK_UART3:
        case CLK_UART4:
        case CLK_UART5:
        case CLK_SPI0:
        case CLK_SPI1:
        case CLK_SPI2:
        case CLK_SPI3:
        case CLK_I2C0:    
        case CLK_I2C1: 
        case CLK_I2S0:
        case CLK_I2S1:
        case CLK_ADC0:
        case CLK_ADC1:
        case CLK_FLASH:
        case CLK_PORTA:
        case CLK_PORTB:
        case CLK_PORTC:
        case CLK_PORTD:
        case CLK_PORTE:
            div = (mod_p->BF.CLKDIV + 1U);
            switch(mod_p->BF.CLKMUX)
            {
                case CLK_SRC_LPO32K:
                    freq = 32000U;
                    break;
            
                case CLK_SRC_OSC32K:
                    freq = 32768U;
                    break;

                case CLK_SRC_FIRC:
                   freq = 64000000U;
                   break;

                case CLK_SRC_HSOSC:
                    freq = oscFreq;
                    break;
                
                case CLK_SRC_PLL:
                    freq = CLK_GetPLLFreq(PLL_HSOSC_CLK, oscFreq);
                    break;

                case CLK_SRC_SLOW:
                    div = (SCC->SCC_CST.DIVCORE + 1U);
                    div *= (SCC->SCC_CST.DIVSLOW + 1U);
                    freq = CLK_GetSysClkFreq(oscFreq);
                    break;
            
                default:
                    break;
            }
            break;
        
        case CLK_CORE:
            div = (SCC->SCC_CST.DIVCORE + 1U);
            freq = CLK_GetSysClkFreq(oscFreq);
            break;
        
        case CLK_BUS:
            div = (SCC->SCC_CST.DIVCORE + 1U);
            div *= (SCC->SCC_CST.DIVBUS + 1U);
            freq = CLK_GetSysClkFreq(oscFreq);
            break;
        
        case CLK_SLOW:
            div = (SCC->SCC_CST.DIVCORE + 1U);
            div *= (SCC->SCC_CST.DIVSLOW + 1U);
            freq = CLK_GetSysClkFreq(oscFreq);
            break;

        default:
            break;
    }
    
    return freq/div;
    
}

/****************************************************************************//**
 * @brief      Get the clock source status
 *
 * @param[in]  clockSource: clock source
 *                              -CLK_SRC_NO
 *                              -CLK_SRC_LPO32K
 *                              -CLK_SRC_OSC32K
 *                              -CLK_SRC_FIRC
 *                              -CLK_SRC_HSOSC
 *                              -CLK_SRC_PLL
 *
 * @return     The clock source status
 *
 *******************************************************************************/
FlagStatus_t CLK_GetClkStatus(CLK_Src_t clockSource)
{
    FlagStatus_t bitStatus = RESET;

    switch(clockSource)
    {
        case CLK_SRC_LPO32K:
            bitStatus = ((PMU->PMU_LPO_32K_CFG.LPO_CLK_READY != 0U) ? SET :
                              RESET);
            break;
        
        case CLK_SRC_FIRC:
            bitStatus = ((SCC->SCC_FIRCCS.FIRCRDY != 0U) ? SET : RESET);
            break;

        case CLK_SRC_OSC32K:
            bitStatus = ((RTC->RTC_CSR.OSC_RDY != 0U) ? SET : RESET);
            break;

        case CLK_SRC_HSOSC:
            bitStatus = ((SCC->SCC_OSCCS.OSCRDY != 0U) ? SET : RESET);
            break;

        case CLK_SRC_PLL:
            bitStatus = ((SCC->SCC_SPLLCS.SPLLRDY != 0U) ? SET : RESET);
            break;

        default:
            break;
    }

    return bitStatus;
}

/****************************************************************************//**
 * @brief      Wait the clock source status until it is ready
 *
 * @param[in]  clockSource: the clock source to be waited
 *                              -CLK_SRC_NO
 *                              -CLK_SRC_LPO32K
 *                              -CLK_SRC_OSC32K
 *                              -CLK_SRC_FIRC
 *                              -CLK_SRC_HSOSC
 *                              -CLK_SRC_PLL
 *
 * @return     SUCC -- the clock is ready
 *             ERR -- time out
 *
 *******************************************************************************/
ResultStatus_t CLK_WaitClkReady(CLK_Src_t clockSource)
{
    volatile uint32_t localCnt = 0;

    switch(clockSource)
    {
        case CLK_SRC_LPO32K:
		{
            while(1)
            {
                if(PMU->PMU_LPO_32K_CFG.LPO_CLK_READY != 0U)
                {
                    return SUCC;
                }
                else if(localCnt > CLK_WAIT_CNT)
                {
                    return ERR;
                }
                else
                {
                    localCnt++;
                }               
            }
            break;
		}
        case CLK_SRC_FIRC:
		{
            while(true)
            {
                if(SCC->SCC_FIRCCS.FIRCRDY == 1U)
                {
                    return SUCC;
                }
                else if(localCnt > CLK_WAIT_CNT)
                {
                    return ERR;
                }
                else
                {
                    localCnt++;
                }                
            }
            break;
		}
        case CLK_SRC_OSC32K:
		{
            while(true)
            {
                if(RTC->RTC_CSR.OSC_RDY == 1U)
                {
                    return SUCC;
                }
                else if(localCnt > CLK_OSC32K_WAIT_CNT)
                {
                    return ERR;
                }
                else
                {
                    localCnt++;
                }
            }
            break;
		}
        case CLK_SRC_HSOSC:
		{
            while(true)
            {
                if(SCC->SCC_OSCCS.OSCRDY == 1U)
                {
                    return SUCC;
                }
                else if(localCnt > CLK_WAIT_CNT)
                {
                    return ERR;
                }
                else
                {
                    localCnt++;
                }
            }
            break;
		}
        case CLK_SRC_PLL:
		{
            while(true)
            {
                if(SCC->SCC_SPLLCS.SPLLRDY == 1U)
                {
                    return SUCC;
                }
                else if(localCnt > CLK_WAIT_CNT)
                {
                    return ERR;
                }
                else
                {
                    localCnt++;
                }
            }
            break;
		}
        default:
		{
			return ERR;
            break;
		}
    }
}

/***************************************************************************//**
 * @brief      Config and Enable clock output
 *
 * @param[in]  outSrc:  Select the clock source to be output.
 *                          -CLK_OUT_FIRC
 *                          -CLK_OUT_HSOSC
 *                          -CLK_OUT_PLL
 *                          -CLK_OUT_SLOW
 *                          -CLK_OUT_BUS
 *                          -CLK_OUT_CORE
 *                          -CLK_OUT_OSC32K
 *                          -CLK_OUT_LPO32K
 * @param[in]  divider: output clock divider
 *                          -CLK_OUT_DIV_1
 *                          -CLK_OUT_DIV_2
 *                          -CLK_OUT_DIV_4
 *                          -CLK_OUT_DIV_8
 *
 * @return none
 *
 ******************************************************************************/
void CLK_ClkOutEnable(CLK_OutSrc_t outSrc, CLK_OutDiv_t divider)
{
    /*Disable clock out first before switching*/
    SCM->SCM_CHIPCTL.CLKOUTEN = 0;

    switch(outSrc)
    {
        case CLK_OUT_HSOSC:
        case CLK_OUT_FIRC:
        case CLK_OUT_PLL:
        case CLK_OUT_SLOW:
        case CLK_OUT_BUS:
        case CLK_OUT_CORE:
            SCM->SCM_CHIPCTL.CLKOUTSEL = 0;
            SCC->SCC_CLKOUTCFG.CLKOUTSEL = (uint32_t)outSrc;
            break;

        case CLK_OUT_OSC32K:
            SCM->SCM_CHIPCTL.CLKOUTSEL = 1;
            break;
    
        case CLK_OUT_LPO32K:
            SCM->SCM_CHIPCTL.CLKOUTSEL = 2;
            break;

        default:
            break;
    }

    SCM->SCM_CHIPCTL.CLKOUTDIV = (uint32_t)divider;

    /* Enable clock out */
    SCM->SCM_CHIPCTL.CLKOUTEN = 1;
}

/***************************************************************************//**
 * @brief      Disable clock output
 *
 * @param[in]  none
 *
 * @return none
 *
 ******************************************************************************/
void CLK_ClkOutDisable(void)
{
    SCM->SCM_CHIPCTL.CLKOUTEN = 0U;
}

/***************************************************************************//**
 * @brief      install call back function
 *
 * @param[in]  intId: select the interrupt
 *                      -CLK_INT_HSOSCLOC
 *                      -CLK_INT_FIRCLOC
 *                      -CLK_INT_PLLLOC
 *                      -CLK_INT_ALL
 * @param[in]  cbFun: pointer to callback function
 *
 * @return none
 *
 ******************************************************************************/
void CLK_InstallCallBackFunc(CLK_Int_t intId,isr_cb_t * cbFun)
{
    sccIsrCbFunc[intId] = cbFun;
}

/***************************************************************************//**
 * @brief      Clear Interrupt status
 *
 * @param[in]  intId: select the interrupt
 *                      -CLK_INT_HSOSCLOC
 *                      -CLK_INT_FIRCLOC
 *                      -CLK_INT_PLLLOC
 *                      -CLK_INT_ALL
 *
 * @return none
 *
 ******************************************************************************/
void CLK_IntClear(CLK_Int_t intId)
{
    if((intId == CLK_INT_HSOSCLOC) || (intId == CLK_INT_ALL))
    {
        if(SCC->SCC_OSCCS.LOCK != 0U)
        {
            /* unlock this register */
            SCC_W->SCC_OSCCS = 0x5B000000U;
        }

        /* clear int status */
        SCC->SCC_OSCCS.OSCLOC = 1U;
        /* lock */
        SCC->SCC_OSCCS.LOCK = 1U;
    }
    
    if((intId == CLK_INT_FIRCLOC) || (intId == CLK_INT_ALL))
    {
        if(SCC->SCC_FIRCCS.LOCK != 0U)
        {
            /* unlock this register */
            SCC_W->SCC_FIRCCS = 0x5B000000U;
        }

        /* clear int status */
        SCC->SCC_FIRCCS.FIRCLOC = 1U;
        /* lock */
        SCC->SCC_FIRCCS.LOCK = 1U;
    }

    if((intId == CLK_INT_PLLLOC) || (intId == CLK_INT_ALL))
    {
        if(SCC->SCC_SPLLCS.LOCK != 0U)
        {
            /* unlock this register */
            SCC_W->SCC_SPLLCS = 0x5B000000U;
        }

        /* clear int status */
        SCC->SCC_SPLLCS.LOL = 1U;
        /* lock */
        SCC->SCC_SPLLCS.LOCK = 1U;
    }
}

/** @} end of group Clock_Public_Functions */

/** @} end of group Clock */

/** @} end of group Z20K14XM_Peripheral_Driver */
